#include <boost/bind.hpp>

#include "ASyncConnection.h"
#include "Request.h"

using namespace boost::asio;
using namespace tbb;


boost::array<unsigned char, 16000> ASyncConnection::buf;


ASyncConnection::ASyncConnection(ServerInfo &Info, size_t SocketCount)
{
	for (size_t i = 0; i < SocketCount; i++)
	{
		// Creating socket
		ip::tcp::socket *s = new ip::tcp::socket(_service);

		// Sending data.
		Stats::GetRef()->RegisterStartedRequest();

		s->async_connect(ip::tcp::endpoint(Info.GetIpAddress(), Info.GetPort()),
					     boost::bind(&ASyncConnection::connectHandler, Info, s,
						 tick_count::now(), placeholders::error));
	}

    _service.run();
}

void ASyncConnection::connectHandler(ServerInfo &Info, ip::tcp::socket *s, tick_count t_start, const boost::system::error_code &error)
{
	Stats::GetRef()->RegisterConnect();

	if (error)
	{
		printf("Error: %s\n", error.message().c_str());

		// Starting new connection.
		s->close();
		Stats::GetRef()->RegisterRequest(false, tick_count::now() - t_start);
		Stats::GetRef()->RegisterStartedRequest();

		s->async_connect(ip::tcp::endpoint(Info.GetIpAddress(), Info.GetPort()),
					     boost::bind(&ASyncConnection::connectHandler,
									 Info, s, tick_count::now(),
									 placeholders::error));
	}
    else
	{
		// Sending request.
		async_write(*s, buffer(request),
						boost::bind(&ASyncConnection::writeHandler,
									Info, s, tick_count::now(),
									placeholders::error,
									placeholders::bytes_transferred));
    }
}

void ASyncConnection::readHandler(ServerInfo &Info, ip::tcp::socket *s, tick_count t_start,
							      const boost::system::error_code &error, size_t bytes_transferred)
{
	// Registering processed request
    Stats::GetRef()->RegisterRequest(!error || error == error::eof, tick_count::now() - t_start);

	// Reopening socket
	s->close();
	Stats::GetRef()->RegisterStartedRequest();

	s->async_connect(ip::tcp::endpoint(Info.GetIpAddress(), Info.GetPort()),
				     boost::bind(&ASyncConnection::connectHandler,
								 Info, s, tick_count::now(),
								 placeholders::error));
}

void ASyncConnection::writeHandler(ServerInfo &Info, ip::tcp::socket *s, tick_count t_start,
                                   const boost::system::error_code &error, size_t bytes_transferred)
{
	Stats::GetRef()->RegisterWrite();

	// Request has been sent. Receiving answer.
	async_read(*s, buffer(buf),
					boost::bind(&ASyncConnection::readHandler,
						  		Info, s, t_start,
								placeholders::error,
								placeholders::bytes_transferred));
}